#include"../include/common_buf.h"
#include <sys/ioctl.h>
#include <string.h>
#include<assert.h>
common_buf::common_buf(){
    buf=nullptr;
}

common_buf::~common_buf(){
    clear();
}

void common_buf::pop(int len){
    assert(buf!=nullptr&&len<=buf->_length);
    buf->pop(len);  //处理长度为len的数据
    if(buf->_length==0){
        //如果为处理的数据长度为0，将内存块放回内存池
        buf_pool::Getinstance()->revert(buf);
        buf=nullptr;
    }
}

void common_buf::clear(){
    if(buf!=nullptr){
        buf_pool::Getinstance()->revert(buf);
        buf=nullptr;
    }
}

const int common_buf::length(){
    return buf!=nullptr?buf->_length:0;
}


//从一个fd中读取数据到reactor_buf中
int input_buf::read_data(int fd)
{
    int need_read;//硬件有多少数据可以读

    //一次性读出所有的数据
    //需要给fd设置FIONREAD,
    //得到read缓冲中有多少数据是可以读取的
    if (ioctl(fd, FIONREAD, &need_read) == -1) {
        fprintf(stderr, "ioctl FIONREAD\n");
        return -1;
    }

    
    if (buf== nullptr) {
        //如果io_buf为空,从内存池申请
        buf = buf_pool::Getinstance()->alloc_buf(need_read);
        if (buf == NULL) {
            fprintf(stderr, "no idle buf for alloc\n");
            return -1;
        }
    }
    else {
        //如果io_buf可用，判断是否够存
        assert(buf->_head == 0);
        if (buf->_capacity - buf->_length < (int)need_read) {
            //不够存，冲内存池申请
            io_buf *new_buf = buf_pool::Getinstance()->alloc_buf(need_read+buf->_length);
            if (new_buf == NULL) {
                fprintf(stderr, "no ilde buf for alloc\n");
                return -1;
            }
            //将之前的_buf的数据考到新申请的buf中
            new_buf->copy(buf);
            //将之前的_buf放回内存池中
            buf_pool::Getinstance()->revert(buf);
            //新申请的buf成为当前io_buf
            buf = new_buf;
        }
    }

    //读取数据
    int already_read = 0;
    do { 
        //读取的数据拼接到之前的数据之后
        if(need_read == 0) {
            //可能是read阻塞读数据的模式，对方未写数据
            already_read = read(fd, buf->_data + buf->_length, m4K);
        } else {
            already_read = read(fd, buf->_data + buf->_length, need_read);
        }
    } while (already_read == -1 && errno == EINTR); //systemCall引起的中断 继续读取
    if (already_read > 0)  {
        if (need_read != 0) {
            assert(already_read == need_read);
        }
        buf->_length += already_read;
    }
    
    return already_read;
}

//取出读到的数据
const char *input_buf::data() 
{
    return buf != NULL ? buf->_data + buf->_head : NULL;
}


//重置缓冲区
void input_buf::adjust()
{
    if (buf != NULL) {
        buf->adjust();
    }
}



//将一段数据 写到一个reactor_buf中
int output_buf::send_data(const char *data, int datalen)
{
    if (buf == nullptr) {
        //如果io_buf为空,从内存池申请
        buf = buf_pool::Getinstance()->alloc_buf(datalen);
        if (buf == nullptr) {
            fprintf(stderr, "no idle buf for alloc\n");
            return -1;
        }
    }
    else {
        //如果io_buf可用，判断是否够存
        assert(buf->_head == 0);
        if (buf->_capacity - buf->_length < datalen) {
            //不够存，冲内存池申请
            io_buf *new_buf = buf_pool::Getinstance()->alloc_buf(datalen+buf->_length);
            if (new_buf == nullptr) {
                fprintf(stderr, "no ilde buf for alloc\n");
                return -1;
            }
            //将之前的_buf的数据考到新申请的buf中
            new_buf->copy(buf);
            //将之前的_buf放回内存池中
            buf_pool::Getinstance()->revert(buf);
            //新申请的buf成为当前io_buf
            buf = new_buf;
        }
    }

    //将data数据拷贝到io_buf中,拼接到后面
    memcpy(buf->_data + buf->_length, data, datalen);
    buf->_length += datalen;

    return 0;
}

//将reactor_buf中的数据写到一个fd中
int output_buf::write_data(int fd)
{
    assert(buf != NULL && buf->_head == 0);

    int already_write = 0;

    do { 
        already_write = write(fd, buf->_data, buf->_length);
    } while (already_write == -1 && errno == EINTR); //systemCall引起的中断，继续写


    if (already_write > 0) {
        //已经处理的数据清空
        buf->pop(already_write);
        //未处理数据前置，覆盖老数据
        buf->adjust();
    }

    //如果fd非阻塞，可能会得到EAGAIN错误
    if (already_write == -1 && errno == EAGAIN) {
        already_write = 0;//不是错误，仅仅返回0，表示目前是不可以继续写的
    }

    return already_write;
}